/*
 * forwarder.cpp
 *
 *  Created on: Dec 24, 2013
 *      Author: m
 */

#include "MessageQueue.h"
#include "ColaRemotaComun.h"
#include "ArchivoIni.h"
#include "StringUtils.h"
#include "CPrinter.h"

#define FWD_BROKERID_ARG 1
#define FWD_BROKERIP_ARG 2

using ipc::MessageQueue;
using ipc::CPrinter;

int main ( int argc, char* argv[] )
{
    int socket = -1;
    int puertoEntrada;
    int brokerId;
    std::string brokerIP;

    CPrinter::setHeader("forwarder");

    if ( argc != 3 )
    {
        CPrinter::printErr( "Error: Cantidad de argumentos invalida" );
        CPrinter::printErr( "USO: %s [broker ID] [broker IP]", argv[0] );
        exit(1);
    }

    brokerId = StringUtils::StringToNumber<int>( argv[FWD_BROKERID_ARG] );
    brokerIP = argv[FWD_BROKERIP_ARG];

    CPrinter::setHeader( "forwarder", brokerId );

    CPrinter::printOut( "INICIADO" );

    MessageQueue<PaqueteColaRemota> colaMensajes =
            MessageQueue<PaqueteColaRemota>::get( IPC_BASEFILE, COLA_MENSAJES_BROKER );

    // Leer el puerto del servicio de un archivo
    ArchivoIni configFile( CR_CONFIG_FILE );
    puertoEntrada = StringUtils::StringToNumber<int>( configFile.getValue( "puertoEntrada" ) );

    // Me conecto al puerto de Entrada del servidor (reintento hasta que pueda)
    while ( socket < 0 )
    {
        socket = tcpopact( brokerIP.c_str(), puertoEntrada );

        if ( socket <= 0 )
        {
            if ( socket < -2 )
            {
                CPrinter::printErr( "No se pudo conectar al broker %d: %s", brokerId, brokerIP.c_str() );
                CPrinter::printErr( "Reintentando en 30 segundos" );

                close( -socket );
                sleep(30);
            }
            else
            {
                CPrinter::printErr( "ERROR: Se produjo un error fatal al intentar conectarse al broker." );
                exit(1);
            }
        }
    }

    CPrinter::printOut( "CONECTADO" );

    while ( true )
    {
        PaqueteColaRemota msg;
        int ack;

        // Leo un paquete para el broker al que estoy forwardeando de la cola de mensajes
        msg = colaMensajes.get( brokerId );

        // Lo mando por el socket hacia el broker que corresponda
        bool envioOk = enviar( socket, &msg, sizeof( PaqueteColaRemota ) ) > 0;

        bool recepcionOk = recibir( socket, &ack, sizeof( int ) ) > 0;

        if ( envioOk && recepcionOk )
        {
            if ( ack != 0 )
            {
                CPrinter::printErr( "Error: Error en el ACK" );
                exit( 1 );
            }
        }
        else
        {
            // Vuelvo a poner el mensaje en la cola
            // TODO: Mejorar esto, ya que el mensaje queda al final de la cola!
            CPrinter::printErr( "Error: El socket se cerro del otro lado!" );

            colaMensajes.put( brokerId, msg );
            exit( 1 );
        }

        if ( msg.destino > 1024 )
            CPrinter::printOut( "Forwardeando un mensaje de la cola %d al broker %d", msg.destino , brokerId );
    }

    return 0;
}


